<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title>TS100 Translation Editor</title>

		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script src="translations_commons.js"></script>
		<script src="translations_def.js"></script>
		<script>

	var app;
	var defMap = {};
	
	function save(){
		saveJSON(app.current, "translation_"+app.current.languageCode.toLowerCase()+".json");
	}

	function view(){
		showJSON(app.current, "translation_"+app.current.languageCode.toLowerCase()+".json");
	}

	function fileChanged(e) {
		var target = e;
		var id = target.id;
		
		var file = target.files[0];
		if (!file) {
			return;
		}
		var fr = new FileReader();
		fr.onload = function(e) {
			try {
				var json = JSON.parse(e.target.result);
			} catch (ex) {
				console.log(ex);
				alert("Invalid JSON file: " + file.name);
				return;
			}
				

			if (id == "referent-lang-file") {
				if (checkTranslationFile(file.name)) {
					app.referent = json;
					app.meta.referentLoaded = true;
				}
			} else if (id == "current-lang-file") {
				if (checkTranslationFile(file.name)) {
					app.current = json;
					app.meta.currentLoaded = true;
				}
			} 		
			synchronizeData();
		}
		fr.readAsText(file);
		
	}
	
	function synchronizeData() {
		app.obsolete = {};
		copyMissing(app.def.messages, app.referent.messages, app.current.messages);
		copyMissing(app.def.characters, app.referent.characters, app.current.characters);
		copyMissing(app.def.menuGroups, app.referent.menuGroups, app.current.menuGroups);
		copyMissing(app.def.menuOptions, app.referent.menuOptions, app.current.menuOptions);
	}
	
	/**
	 * Copy all missing properties from referent to current
	 * for each entry in definition
	 */
	function copyMissing(defList, referentMap, currentMap) {
		if (!isDefined(defList) || !isDefined(referentMap) || !isDefined(currentMap)) {
			return;
		}
		var len = defList.length;
		for (var i = 0; i < len; i++) {
			var id = defList[i].id;
			if (!isDefined(referentMap[id])) {
				referentMap[id] = '';
			}
			if (!isDefined(currentMap[id])) {
				currentMap[id] = referentMap[id];
			}
		}
		processObsolete(defList, currentMap);
	}

	// Passes through all entries from the given map.
	// If a corresponding entry is not found in the defList, it is removed from the map, and added into the obsolete map.
	function processObsolete(defList, map) {
		// Index list to map for faster search
		var defMap = copyArrayToMap(defList);
		Object.keys(map).forEach(function(key) {
			if (!isDefined(defMap[key])) {
				app.obsolete[key] = { id : key, value : map[key]};
				delete map[key];
			}
		});
	}

	function length(obj, mode) {
		if (!isDefined(mode) || mode == 0) {
			// return direct length
			return obj.length;
		} else if (mode == 1) {
			// return length of text property
			return obj.text.length;
		} else if (mode == 2) {
			// return the longest length in text2 array
			return Math.max(isDefinedNN(obj.text2[0]) ? obj.text2[0].length : 0, isDefinedNN(obj.text2[1]) ? obj.text2[1].length : 0);
		}
	}
	
	function getAttribute(obj, attribute, isDouble) {
		var d = isDouble ? "2" : "";
		var v = obj[attribute+d];
		if (isDefined(v))
			return v;
		return obj[attribute];
	}
	
	function loaded() {
		app = new Vue({
			el : '#app',
			data : {
				meta : {
					referentLoaded : false,
					currentLoaded : false,
				},
				def : {
				},
				referent : {
					messages : {}
				},
				current : {
					loaded: false,
				},
				obsolete : {},
				menuDouble : false
			},
			methods : {
				validateInput: function(valMap, id, mode) {
					var d = defMap[id];
					var vLen = 0;
					if (!isDefined(mode))
						mode = 0;
						
					try {
						// Sum for complex length
						for (var i = 0; i < d.lenSum.fields.length; i++) {
							vLen += length(valMap[d.lenSum.fields[i]], mode);
						}
						d = d.lenSum;
					} catch (e) {
						// Single field length
						vLen = length(valMap[id], mode);
					}
					var maxLen = getAttribute(d, 'maxLen', mode == 2);
					var minLen = getAttribute(d, 'minLen', mode == 2);
					var len = getAttribute(d, 'len', mode == 2);
					if (isNumber(maxLen) && vLen > maxLen
						|| isNumber(minLen) && vLen < minLen
						|| isNumber(len) && vLen != len
						) {
						return "invalid";
					}
				},
				
				constraintString: function(e, d) {
					var str = "";
					var delim = "";
					var v;
					if (!isDefined(d) || d == false) {
						d = "";
					} else {
						d = "2";
					}

					if (isDefinedNN(e.lenSum)) {
						str = "len("+(e.lenSum.fields+"").replace(/,/g," + ")+") -> ";
						e = e.lenSum;
					}
					v = getAttribute(e, 'len', d);
					if (isNumber(v)) {
						str += delim + "len=" + v;
						delim = " and ";
					}
					v = getAttribute(e, 'minLen', d);
					if (isNumber(v)) {
						str += delim + "len>=" + v;
						delim = " and ";
					}
					v = getAttribute(e, 'maxLen', d);
					if (isNumber(v)) {
						str += delim + "len<=" + v;
						delim = " and ";
					}
					return str;
				}
			}
		});
		app.def = def;
		copyArrayToMap(app.def.messages, defMap);
		copyArrayToMap(app.def.characters, defMap);
		copyArrayToMap(app.def.menuGroups, defMap);
		copyArrayToMap(app.def.menuOptions, defMap);
	}
	
	window.onload=loaded;
</script>
	<link href="translations.css" rel="stylesheet" type="text/css">
	</head>
	<body>

		<div id="app">
			<h1>TS100 Translation Editor<span v-if="meta.currentLoaded"> - {{ current.languageLocalName }} [{{current.languageCode}}]</span></h1>
			<table class="header data">
				<tr>
					<td class="label">Referent Language</td>
					<td class="value">
						<input type="file" id="referent-lang-file" onchange="fileChanged(this)" accept=".json">
						<span class="selected" v-if="meta.referentLoaded">{{ referent.languageLocalName }} [{{referent.languageCode}}]</span>
					</td>
				</tr>
				<tr v-if="meta.referentLoaded">
					<td class="label">Current Language</td>
					<td class="value">
						<input type="file" id="current-lang-file" onchange="fileChanged(this)" accept=".json">
						<span class="selected" v-if="meta.currentLoaded">{{ current.languageLocalName }} [{{current.languageCode}}]</span>
					</td>
				</tr>
				<tr v-if="meta.currentLoaded">
					<td class="label">Local Language Code</td>
					<td class="value"><input type="text" v-model="current.languageCode" maxlength="8" v-on:change="current.languageCode=current.languageCode.toUpperCase()" class="short"></td>
				</tr>
				<tr v-if="meta.currentLoaded">
					<td class="label">Local Language Name</td>
					<td class="value"><input type="text" v-model="current.languageLocalName" class="short"></td>
				</tr>
			</table>
			
			<div v-if="def.messages && referent.messages && current.messages">

				<div class="footer">
					<input type="button" value="Save" onclick="save()">
					<input type="button" value="View" onclick="view()">
				</div>
				
				<div v-if="Object.keys(obsolete).length > 0">
					<h2>Obsolete</h2>
					<table class="data">
						<tr v-for="entry in obsolete">
							<td class="label"><div class="stringId">{{entry.id}}</div></td>
							<td class="value"><div class="ref">{{entry.value}}</div></td>
						</tr>
					</table>
				</div>

				<h2>Messages and Strings</h2>
				<table class="data">
					<tr v-for="message in def.messages" v-bind:class="validateInput(current.messages, message.id)">
						<td class="label"><div class="stringId">{{message.id}}</div></td>
						<td class="value">
							<div class="constraint">{{constraintString(message)}}</div>
							<div class="ref">{{referent.messages[message.id]}}</div>
							<div class="note" v-if="message.note">{{message.note}}</div>
							<div class="tran"><input :id="'in_'+message.id" type="text" v-model="current.messages[message.id]" v-bind:class="{unchanged : current.messages[message.id] == referent.messages[message.id], empty : current.messages[message.id]==''}"></div>
						</td>
					</tr>
				</table>

				<h2>Characters</h2>
				<table class="data">
					<tr v-for="char in def.characters" v-bind:class="validateInput(current.characters, char.id)">
						<td class="label"><div class="stringId">{{char.id}}</div></td>
						<td class="value">
							<div class="constraint">{{constraintString(char)}}</div>
							<div class="ref">{{referent.characters[char.id]}}</div>
							<div class="tran"><input type="text" v-model="current.characters[char.id]" v-bind:class="{unchanged : current.characters[char.id] == referent.characters[char.id], empty : current.characters[char.id].length != 1}"></div>
						</td>
					</tr>
				</table>

				<h2>Menu Groups</h2>
				<table class="data">
					<tr v-for="menu in def.menuGroups" v-bind:class="validateInput(current.menuGroups, menu.id, 2)">
						<td class="label"><div class="stringId">{{menu.id}}</div></td>
						<td class="value">
							<div class="label">Menu Name</div>
							<div class="constraint">{{constraintString(menu)}}</div>
							<div class="ref">{{referent.menuGroups[menu.id].text2}}</div>
							<div class="tran" v-bind:class="{unchanged : current.menuGroups[menu.id].text2[0] == referent.menuGroups[menu.id].text2[0] && current.menuGroups[menu.id].text2[1] == referent.menuGroups[menu.id].text2[1], empty : current.menuGroups[menu.id].text2[0] == '' || current.menuGroups[menu.id].text2[1] == ''}"><input type="text" v-model="current.menuGroups[menu.id].text2[0]"><input type="text" v-model="current.menuGroups[menu.id].text2[1]"></div>
							<div class="label">Description</div>
							<div class="ref">{{referent.menuGroups[menu.id].desc}}</div>
							<div class="tran"><input type="text" v-model="current.menuGroups[menu.id].desc" v-bind:class="{unchanged : current.menuGroups[menu.id].desc == referent.menuGroups[menu.id].desc, empty : current.menuGroups[menu.id].desc == ''}"></div>
						</td>
					</tr>
				</table>

				<h2>Menu Options</h2>
				<table class="data">
					<tr>
						<td class="label">Menu Type</td>
						<td class="value">
							<select v-model="current.menuDouble" v-on:change="current.menuDouble = current.menuDouble=='true'">
								<option value="false">Single-Line</option>
								<option value="true">Double-Line</option>
							</select>
						</td>
					</tr>
					<tr v-for="menu in def.menuOptions" v-bind:class="validateInput(current.menuOptions, menu.id, (current.menuDouble ? 2 : 1))">
						<td class="label"><div class="stringId">{{menu.id}}</div></td>
						<td class="value">
							<div v-bind:class="{hidden : current.menuDouble}">
								<div class="label">Menu Name (Single-Line)</div>
								<div class="constraint">{{constraintString(menu, current.menuDouble)}}</div>
								<div class="ref">{{referent.menuOptions[menu.id].text}}</div>
								<div class="tran"><input type="text" v-model="current.menuOptions[menu.id].text" v-bind:class="{unchanged : current.menuOptions[menu.id].text == referent.menuOptions[menu.id].text, empty : current.menuOptions[menu.id].text == ''}"></div>
							</div>
							<div v-bind:class="{hidden : !current.menuDouble}">
								<div class="label">Menu Name (Double-Line)</div>
								<div class="constraint">{{constraintString(menu, current.menuDouble)}}</div>
								<div class="ref">{{referent.menuOptions[menu.id].text2}}</div>
								<div class="tran" v-bind:class="{unchanged : current.menuOptions[menu.id].text2[0] == referent.menuOptions[menu.id].text2[0] && current.menuOptions[menu.id].text2[1] == referent.menuOptions[menu.id].text2[1], empty : current.menuOptions[menu.id].text2[0] == '' || current.menuOptions[menu.id].text2[1] == ''}"><input type="text" v-model="current.menuOptions[menu.id].text2[0]"><input type="text" v-model="current.menuOptions[menu.id].text2[1]"></div>
							</div>
							<div class="label">Description</div>
							<div class="ref">{{referent.menuOptions[menu.id].desc}}</div>
							<div class="tran"><input type="text" v-model="current.menuOptions[menu.id].desc" v-bind:class="{unchanged : current.menuOptions[menu.id].desc == referent.menuOptions[menu.id].desc, empty : current.menuOptions[menu.id].desc == ''}"></div>
						</td>
					</tr>
				</table>

				<div class="footer">
					<input type="button" value="Save" onclick="save()">
					<input type="button" value="View" onclick="view()">
				</div>
			</div>
		</div>
	</body>
</html>